#pragma once
#include <iostream>
#include <cstring>
#include <string>
#include <functional>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "Nocopy.hpp"
#include "Log.hpp"
#include "InetAddr.hpp"

using func_t = std::function<std::string(std::string)>;

using namespace LOGSpace;
static int gDEFAULT = -1;
static uint16_t gPORT = 8888;
enum
{
    SERVER_ERROR = 1,
    BIND_ERROR,
    DICT_ERROR
};
// v2: dict---与IO解耦
class UdpServer : public Nocopy
{
public:
    UdpServer(func_t func, int sockfd = gDEFAULT, uint16_t port = gPORT)
        : _func(func),
          _sockefd(sockfd),
          _port(port)
    {
    }
    ~UdpServer()
    {
        // close sockfd
        if (_sockefd > 0)
            ::close(_sockefd);
    }
    void InitServer()
    {
        _sockefd = ::socket(AF_INET, SOCK_DGRAM, 0);
        if (_sockefd < 0)
        {
            LOG(FATAL, "Create socket fault!\n");
            exit(SERVER_ERROR);
        }
        LOG(DEBUG, "socket create success,sockfd = %d\n", _sockefd);
        struct sockaddr_in localdata;
        // 初始化
        memset(&localdata, 0, sizeof(localdata));
        // 填充loaldata
        localdata.sin_family = AF_INET;
        localdata.sin_port = htons(_port);
        // localdata.sin_addr.s_addr = inet_addr(_ip.c_str());
        localdata.sin_addr.s_addr = INADDR_ANY; //---0
        // loaldata设置进内核--bind
        int n = ::bind(_sockefd, (struct sockaddr *)(&localdata), sizeof(localdata));
        if (n < 0)
        {
            LOG(FATAL, "bind error! \n");
            exit(BIND_ERROR);
        }
        LOG(DEBUG, "bind sucess!\n");
    }
    void StartServer()
    {
        _isrunning = true;
        char inBuff[1024];
        // 服务器永不退出！
        while (_isrunning)
        {
            struct sockaddr_in src_addr; // 接收“谁”发来的ip和port
            socklen_t len = sizeof(src_addr);
            ssize_t n = recvfrom(_sockefd, inBuff, sizeof(inBuff) - 1, 0, (struct sockaddr *)(&src_addr), &len);
            if (n > 0)
            {
                // uint16_t client_port = ntohs(src_addr.sin_port);

                InetAddr addr(src_addr);
                // std::string client_ip = inet_ntoa(src_addr.sin_addr);

                inBuff[n] = '\0';
                std::cout << "[@" << addr.Ip() << ":" << addr.Port() << "]# " << inBuff << std::endl;

                // 业务逻辑TODO
                std::string result_str = _func(inBuff);

                // return client
                ssize_t sendlen = sendto(_sockefd, result_str.c_str(), result_str.size(), 0,
                                         (struct sockaddr *)(&src_addr), len);
            }
        }
    }

private:
    int _sockefd;
    uint16_t _port;
    bool _isrunning = false;
    func_t _func;
};
